package com.tarena.lbs.marketing.web.service.impl;

import com.tarena.lbs.marketing.web.repository.CouponCodeRepository;
import com.tarena.lbs.marketing.web.repository.CouponRepository;
import com.tarena.lbs.marketing.web.service.CacheService;
import com.tarena.lbs.marketing.web.service.CouponService;
import com.tarena.lbs.marketing.web.service.MarketingActivityService;
import com.tarena.lbs.marketing.web.service.UserReceiveCouponService;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.BasePageList;
import com.tarena.lbs.basic.api.UserGroupApi;
import com.tarena.lbs.common.marketing.enums.ActivityStatusEnum;
import com.tarena.lbs.common.marketing.enums.CouponCodeStatusEnum;
import com.tarena.lbs.common.marketing.enums.MarketingResultEnum;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.common.security.utils.LbsSecurityContenxt;
import com.tarena.lbs.pojo.marketing.bo.CouponBO;
import com.tarena.lbs.pojo.marketing.bo.CouponCodeBO;
import com.tarena.lbs.pojo.marketing.bo.MarketingActivityBO;
import com.tarena.lbs.pojo.marketing.bo.UserReceiveCouponBO;
import com.tarena.lbs.pojo.marketing.dos.CouponDO;
import com.tarena.lbs.pojo.marketing.param.CouponCodeParam;
import com.tarena.lbs.pojo.marketing.param.CouponParam;
import com.tarena.lbs.pojo.marketing.param.UpdateParam;
import com.tarena.lbs.pojo.marketing.param.UserReceiveCouponParam;
import com.tarena.lbs.pojo.marketing.query.CouponQuery;
import com.tarena.lbs.pojo.stock.bo.CouponStockBO;
import com.tarena.lbs.pojo.stock.param.CouponStockParam;
import com.tarena.lbs.stock.api.CouponStockApi;
import io.seata.spring.annotation.GlobalTransactional;
import java.util.List;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

@Service
@Slf4j
public class CouponServiceImpl implements CouponService {

    @Resource
    private CouponStockApi couponStockApi;

    @Resource
    private UserGroupApi userGroupApi;

    @Resource
    private CouponRepository couponRepository;

    @Resource
    private CouponCodeRepository couponCodeRepository;

    @Resource
    private CacheService cacheService;

    @Resource
    private MarketingActivityService marketingActivityService;

    @Resource
    private UserReceiveCouponService userReceiveCouponService;

    @Override
    @GlobalTransactional
    public void insert(CouponParam couponParam) throws BusinessException {
        CouponDO couponDO = couponRepository.insert(couponParam);
        CouponStockParam couponStockParam = new CouponStockParam();
        couponStockParam.setBusinessId(couponParam.getBusinessId());
        couponStockParam.setCouponId(couponDO.getId());
        couponStockParam.setNum(couponParam.getMaxUsageLimit());
        couponStockApi.insertCouponStock(couponStockParam);
    }

    @Override
    public void update(CouponParam couponParam) {
        couponRepository.update(couponParam);
    }

    @Override
    public void updateStatus(UpdateParam updateParam) {
        couponRepository.updateStatus(updateParam);
    }

    @Override
    public BasePageList<CouponBO> list(CouponQuery couponQuery) {
        return couponRepository.list(couponQuery);
    }

    @Override
    public CouponBO getDetail(Integer couponId) {
        return couponRepository.getDetail(couponId);
    }

    @Override
    //@Async("asyncExecutor")
    public void executeAsync(UserReceiveCouponParam param) throws Exception {
        log.info("start executeAsync");
        userReceiveCoupon(param);
        log.info("end executeAsync");
    }

    @Override
    @GlobalTransactional
    public void userReceiveCoupon(UserReceiveCouponParam param) throws Exception {
        //校验用户
        UserPrinciple loginUser = LbsSecurityContenxt.getLoginToken();
        if (loginUser != null) {
            param.setUserId(loginUser.getId());
        }
        //校验优惠券
        CouponBO couponBo = couponRepository.getDetail(param.getCouponId());
        if (couponBo == null || ActivityStatusEnum.DISABLE.getCode().equals(couponBo.getStatus())) {
            throw new BusinessException(MarketingResultEnum.COUPON_NOT_FIND);
        }
        //校验活动
        MarketingActivityBO marketingActivityBO = marketingActivityService.getDetail(param.getActivityId());
        if (marketingActivityBO == null || ActivityStatusEnum.DISABLE.getCode().equals(marketingActivityBO.getStatus())) {
            throw new BusinessException(MarketingResultEnum.ACTIVITY_NOT_FIND);
        }
        //校验用户领取次数
        List<UserReceiveCouponBO> userCouponList = userReceiveCouponService.userCouponList(param.getUserId(), param.getCouponId());
        if (!CollectionUtils.isEmpty(userCouponList) && couponBo.getUsageLimit() !=0 && userCouponList.size() >= couponBo.getUsageLimit()) {
            throw new BusinessException(MarketingResultEnum.COUPON_NOT_CAPACITY);
        }
        //校验用户所属人群
        boolean userValidate = userGroupApi.isUserInTargetGroup(param.getUserId(), marketingActivityBO.getTargetCustomer());
        if (!userValidate) {
            throw new BusinessException(MarketingResultEnum.USER_GROUP_ERROR);
        }
        //校验库存
        CouponStockBO couponStockBO = couponStockApi.getCouponStock(param.getCouponId());
        if (couponStockBO.getNum() <= 0) {
            throw new BusinessException(MarketingResultEnum.COUPON_NOT_CAPACITY);
        }
        //获取券码
        CouponCodeBO couponCodeBO = couponCodeRepository.getCouponCodeDetail(param.getCouponId());
        if (couponCodeBO == null) {
            throw new BusinessException(MarketingResultEnum.COUPON_NOT_CAPACITY);
        }
        //领取优惠券
        param.setCouponCode(couponCodeBO.getCouponCode());
        userReceiveCouponService.insert(param);
        //券码状态变更
        CouponCodeParam couponCodeParam = new CouponCodeParam();
        couponCodeParam.setId(couponBo.getId());
        couponCodeParam.setStatus(CouponCodeStatusEnum.DISABLE.getCode());
        couponCodeRepository.update(couponCodeParam);
        //优惠券数量扣减
        CouponStockParam stockParam = new CouponStockParam();
        stockParam.setNum(1);
        stockParam.setCouponId(param.getCouponId());
        couponStockApi.updateCouponStock(stockParam);

    }

}
